Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

quaternion improvements and new features #43

Merged
merged 38 commits into from
Apr 11, 2018
Merged

quaternion improvements and new features #43

merged 38 commits into from
Apr 11, 2018

Conversation

recp
Copy link
Owner

@recp recp commented Apr 7, 2018

New functions:

  • glm_quat_mat4t(versor q, mat4 dest) - convert quat to mat4 (transposed)
  • glm_quat_mat3(versor q, mat3 dest) - convert quat to mat3
  • glm_quat_mat3t(versor q, mat3 dest) - convert quat to mat3 (transposed)
  • glm_mat4_quat(mat4 m, versor dest) - convert mat4 to quat
  • glm_mat3_quat(mat3 m, versor dest) - convert mat3 to quat
  • glm_quat_conjugate(versor q, versor dest)
  • glm_quat_inv(versor q, versor dest) - inverse of quaternion
  • change WXYZ order to XYZW. (In Progress)
  • change quat_mulvto quat_mul(because we multiply quat with quat, not vector), we may use mulv for multiply quat with vector (In Progress)
  • SSE/SSE2 version for quat_mul (maybe)
  • glm_quat_axis(versor q, vec3 dest) - get axis from quat
  • float glm_quat_real(versor q) - returns w
  • float glm_quat_angle(versor q) - get angle from quat
  • glm_quat_imag(versor q, vec3 dest)
  • glm_quat_imagn(versor q, vec3 dest) - normalized version of `_imag
  • float glm_quat_imaglen(versor q)
  • glm_quat_add(versor p, versor q, versor dest)
  • glm_quat_sub(versor p, versor q, versor dest)
  • rotate vector with quat (glm_quat_roatev(versor q, vec3 v, vec3 dest) maybe)
  • rotate matrix with quat (glm_quat_roate(versor q, mat4 transform, mat4 dest) maybe)
  • update docs (In Progress)
  • tests (In Progress)
  • glm_quat_look(vec3 eye, versor ori, mat4 dest) - create view matrix using quaternion
  • glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest) - creates quaternion for look rotation (source to dest point)

New Helpers:

  • glm_vec4_sqrt(vec4 v, vec4 dest)
  • glm_vec_sqrt(vec3 v, vec3 dest)
  • glm_vec4_sign(vec4 v, vec4 dest)
  • glm_vec_sign(vec3 v, vec3 dest)
  • SSE2 implementation for vec4_dot and vec4_norm2
  • glm_vec_lerp(vec3 from, vec3 to, float t, vec3 dest)
  • glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest)
  • float glm_lerp(float from, float to, float t)
    [DROPPED] - [x] glm_mat4_mulq(mat4 m, versor q, mat4 dest) - multiply mat4 with quat; now we have glm_quat_roate for this purpose
    [DROPPED] - [x] glm_mat4_quat_sse2(mat4 m, versor dest) - convert mat4 to quat (SSE2 version)
    [DROPPED] - [x] glm_quat_slerp_sse2(versor from, versor to, float t, versor dest) - it seems it is not produce correct results, also glm_quat_slerp version is improved and using vec4s no need to write manual SSE codes because vec4 functions are optimized with SIMD functions
    [POSTPONED] - [ ] float glm_quat_euler(versor q, vec3 eulXYZ) - convert quat to euler angles
    [POSTPONED] - [ ] float glm_euler_quat(vec3 eulXYZ, versor dest) - convert euler angles to quat

CRITICAL CHANGES:

  • normalize quaternion (not input itself) in glm_quat_mat4 and glm_quat_mat3 before convert to matrix (if this is not good idea, please let me know)
  • change WXYZ order to XYZW
  • change glm_quat_mulv to glm_quat_mul and use glm_quat_mulvfor multiply quat with vector

recp added 7 commits April 7, 2018 13:46
* the quaternion is used as right matrix
* because it must be unit quaternion and didn't specified this in docs.

* we must provide alternative func for unit quat
* add SSE2 version and optimize scalar version
@recp
Copy link
Owner Author

recp commented Apr 8, 2018

I implemented in "Alternative Method" mentioned in: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm

quaternion.w = sqrt( max( 0, 1 + m00 + m11 + m22 ) ) / 2;
quaternion.x = sqrt( max( 0, 1 + m00 - m11 - m22 ) ) / 2;
quaternion.y = sqrt( max( 0, 1 - m00 + m11 - m22 ) ) / 2;
quaternion.z = sqrt( max( 0, 1 - m00 - m11 + m22 ) ) / 2;
Q.x = _copysign( Q.x, m21 - m12 )
Q.y = _copysign( Q.y, m02 - m20 )
Q.z = _copysign( Q.z, m10 - m01 )

It requires extra sqrt functions but since it requires 4 sqrt I used SIMD instruction here. So without function call and with SINGLE instruction we calculate all sqrt at once, which is good. This is also true for sign function. cglm's sign functions return -1, 0 and +1 which makes the algorithm work (glm_vec4_sign and glm_vec4_sqrt also uses SIMD instructions)

I didn't compare performances between other method and this "alternative" method but since it is possible to write SIMD version I used this one. glm_mat4_quat_sse2 is SIMD version which will be called if SSE2 is supported. No need to call this manually

In the future we may change this if we find better approach...

Also I found this one: https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf which seems interesting but I didn't worke for me, I don't know.

@recp
Copy link
Owner Author

recp commented Apr 8, 2018

One another thing is that, glm_quat_mat3 and glm_quat_mat4 functions didn't normalize the input quaternion, now they normalize the input quat. Because it must be unit quaternion and most user will not aware of this and will get different rotation matrices.

glm don't normalize input quaternion if I read it correctly and I don't know why: https://github.com/g-truc/glm/blob/8390a77b3a278b15259e5ca6e67f7e41badc457b/glm/gtc/quaternion.inl#L619

We should normalize it, and maybe we should provide alternative function which accepts only unit vector.

@recp
Copy link
Owner Author

recp commented Apr 8, 2018

Should we change the order of quaternion members from wxyz to xyzw? Any feedback?

@recp
Copy link
Owner Author

recp commented Apr 8, 2018

Update: I updated matrix to quat code, I was said that I used alternative method but it didn't work well in tests. So I switched to other one, I borrowed mat2quat from Apple's simd library which works well and passes all tests.

@shakesoda
Copy link

switching quat members to xyzw would be consistent with some other math libraries I've used, and my own internal ones. 👍

@recp
Copy link
Owner Author

recp commented Apr 9, 2018

@shakesoda thanks for your feedback[s] 🤗, I thought the same, most libraries use xyzw and making cglm that way would make easier to copy quaternion from one library to another.

Especially new-comers may assume that cglm uses xyzw (it is wxyz for now) but if they construct quaternion manually they will create wrong one and get wrong rotation matrix... wxyz perfectly matches with math expression (w + xi + yj + zk) but I'll change/update it to xyzw in this PR 👍 because in GLSL-like lang/apis quat.w is last element...

One another thing I want to get feedback is that I want to change versor type to quat, but unlike vec3, vec4, mat4... the quat type not seems like a type, it seems like a variable. I don't want conflicts between user variables and cglm types (and system types/macros).

Alternative names:
quat
quat32
quat_t

or we just continue to use versor or just vec4 I'm not sure which one is better. (versor is a type alias of vec4)

PS: I dropped "alternative method" but I created a gist (https://gist.github.com/recp/97d87c8b9c3fe8ac432a865dff3c783d) for it, in the future we may bring it back if we can fix it's numerical errors (probably we will not)

@recp recp added this to the v0.3.6 milestone Apr 9, 2018
recp added 6 commits April 9, 2018 21:54
* convert quaternion multiplication to xyzw
* previous implementation may be wrong, wikipedia version implemented
* implement SSE version
@recp
Copy link
Owner Author

recp commented Apr 10, 2018

Here is the new lookat function:

void glm_quat_look(vec3 eye, versor ori, mat4 dest)

it is similar to glm_lookatand glm_look but unlike them this one creates view matrix using quaternion. Quaternion specifies UP and RIGHT vectors. Also it generates less instructions than glm_lookatand glm_look

Also I postponed quaternion -> euler because we may change euler API later, check this issue: #30

@recp
Copy link
Owner Author

recp commented Apr 10, 2018

Now we also have another option to rotate vectors: Quaternions!

New option:

  • glm_quat_rotatev(versor q, vec3 v, vec3 dest) - rotate vector using quat

Previous options:

  • glm_vec_rotate(vec3 v, float angle, vec3 axis) - rotate vector using angle and axis
  • glm_vec_rotate_m4(mat4 m, vec3 v, vec3 dest) - rotate vector using matrix
  • manual matrix-vector multiplication

Also, added some tests for quaternions everthing looks good except I didn't add tests for slerp and lerp.

  • [bugfix] While comparing glm_quat_rotatev and glm_vec_rotate results I have realized that we should normalize axis in glm_quatv and glm_vec_rotate. Now they are normalized and we get same result in both glm_vec_rotate and glm_quat_rotatev

* glm_quat_rotate is better name to rotate transform matrix using quaternion.
* we may use mat4_mulq in the future for another purpose e.g. left multiplication quat with matrix
@recp
Copy link
Owner Author

recp commented Apr 11, 2018

glm_mat4_mulq is replaced with glm_quat_rotate(mat4 m, versor q, mat4 dest) because glm_quat_rotate seems better name. It rotates existing transform using quaternion

@winduptoy IIRC we have discussed quat order before, I hope you caught WXYZ to XYZW changes and I hope you are ok with this too

I added some tests (and lots of APIs) and everthing looks good, we have better quaternion APIs now.

I'm going to merge this PR after updated docs and change version from v0.3.5 to v0.4.0

@recp recp merged commit 462067c into master Apr 11, 2018
@recp recp deleted the quaternion branch April 11, 2018 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants